﻿package UI {
	
	// associates to "Node" MC graphic in meadanglobe.fla library
	
	import flash.display.*;
	import flash.events.*;
	import flash.text.*;
	import flash.net.*;
	import flash.utils.*;
	import flash.geom.*;
	import support.Vector3;
	import flash.filters.DropShadowFilter;
	import org.papervision3d.objects.*;
	
	import UI.WinDisplay;
	import UI.Pointer;
	
	public class Node extends MovieClip {
		
		// ref
		public var app:*;
		
		// properties
		private var nodeID:int;
		public var id:uint;
		public var title:String;
		public var type:String;
		public var geoPosition:String;
		public var description:String;
		public var latitude:Number;
		public var longitude:Number;
		public var elevation:Number;
		public var contentPath:String;
		
		// positioning
		public var xPos:Number;
		public var yPos:Number;
		public var zPos:Number;
		public var pos:Vector3 = new Vector3();
		private var origXScale:Number;
		private var origYScale:Number;
		public var billboard:Billboard;

		// display
		private var marker:Sprite;
		private var colorCode:uint;
		private var meadanColors:Boolean = true;
		private var invisible:Boolean = false; // ?
		public var titleTextField:TextField;
		
		// NODE CONSTRUCTOR ////////////////////////////////////
		public function Node(xmlPlacemark:XML, data:Object):void {
			initContent(xmlPlacemark, data);
			setType();
			setPosition();
			initTextDisplay();
			//
			addEventListener(Event.ENTER_FRAME, update);
			addEventListener(MouseEvent.CLICK, clickHandler);
			addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
			addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
		}
		
		// INIT CONTENT (KML XML) ///////////////////////////////////////////////////////////////
		// note: KML may be the best standard for geodata integration
		// see: http://code.google.com/apis/kml/documentation
		private function initContent(xmlPlacemark:XML, data:Object):void {
		
		  	// declare a default namespace
			// (inherited from parent node if none declared)
		 	var ns:Namespace = xmlPlacemark.namespace();
		  	default xml namespace = ns;
			
			// extract data from XML //////////////////////////////////////
		    // (assumes all target members are string types)
			
			// from attributes
			id = xmlPlacemark.@id.toString(); 
		    type = xmlPlacemark.@type.toString();
			
			// from elements
			title = xmlPlacemark.name.toString();
		 	contentPath = xmlPlacemark.description.toString();
		  	geoPosition = xmlPlacemark.Point.coordinates.toString();
			
			// parse latitude and longitude from geoPosition
			var geoPos:Array = new Array();
			geoPos = geoPosition.split(",", 3);
			latitude  = geoPos[0];
			longitude = geoPos[1];
			elevation = 0; // (available at geoPos[2])
			
			// convert lat/long to radians
			latitude = Math.PI * latitude / 180;
			longitude = Math.PI * longitude / 180;
			
			// adjust position by radians (1 radian = 57.2958 degrees)
			latitude -= 1.570795765134; // subtract 90 degrees (in radians = 1.570795765134);
			
			// make relative adjustments
			latitude += 0.05;
			longitude -= 0.15; // 
			
			// extract data from data object
			nodeID 		= data.nodeID; 
			app 		= data.app;
			
			// reset namespace to null
			// (this is necessary to avoid: "VerifyError: Error #1025: An invalid register 3 was accessed" )
			default xml namespace = null;
		}
		
		// SET TYPE /////////////////////////////////////////////////////////////////////
		private function setType():void {
			
			switch (type) {
				
				case "0":
					colorCode = 0x000000; // black
					break;
				
				case "1":
					colorCode = 0xE06117; // red
					break;
				
				case "2":
					colorCode = 0x6DC1EF; // blue
					break;
				
				case "3":
					colorCode = 0x7FDD34; // green
					break;
				
				case "4":
					colorCode = 0xD0C32E; // yellow
					break;
					
				case "8":
					colorCode = 0xFFFFFF; // white
					break;
					
				default:
					colorCode = 0xFFFFFF; // white
					break;
			}
			
			if (type != "0") {
				if (!meadanColors) {colorCode = 0xFFFFFF}
				colorTransform(colorCode);
			}
		}
		
		// TRANSFORMATIONS /////////////////////////////////////
		private function colorTransform(colorCode:uint):void {
			
			// change color to type
			var colorInfo:ColorTransform 
				= this.point.transform.colorTransform;
			colorInfo.color = colorCode;
			this.point.transform.colorTransform = colorInfo;
		
			// apply the drop shadow
			var shadow:DropShadowFilter = new DropShadowFilter();
			shadow.distance = 7;
			shadow.angle 	= 35;
			this.shadowpoint.filters = [shadow];
		
		}
		
		// SET POSITION ////////////////////////////////////////
		private function setPosition():void {
			
			// latitude and longitude conversion formula
			xPos = (app.radius) * Math.sin(latitude) * Math.cos(longitude);
			zPos = (app.radius) * Math.sin(latitude) * Math.sin(longitude);
			yPos = (app.radius) * Math.cos(latitude);
			
			pos = new Vector3(xPos, yPos, zPos);
			
			origXScale = this.scaleX;
			origYScale = this.scaleY;
		}
		
		// UPDATE /////////////////////////////////////////////////////////////////////
		public function update(event:Event):void {
			render();
		}
		
		// RENDER (position node in 3D space) ////////////////////////////////////////
		private function render():void {
			
			var tempPos:Vector3;
			
			// coordinate rotation on Y
			tempPos = pos.rotate('y', app.angleY);
			// coordinate rotation on X
			tempPos = pos.rotate('x', app.angleX); //  tempPos.rotate('x', app.angleX);
			
			// get virtual z pos
			tempPos.z = billboard.screen.z;
			
			// set in 3D space
			var scale:Number = app.focalLength / (app.focalLength + tempPos.z) * 1.2; //
			tempPos = tempPos.subtract(app.vanishingPoint);
				
			// adjust alpha transparency for z dimension (optional)
			//alpha = (1 - (tempPos.z + app.radius * 2) / (app.radius * 2)) * 0.3 + 0.7;
			
			// adjust alpha transparency for z dimension on just the shadow (optional)
			this.shadowpoint.alpha = (1 - (tempPos.z + app.radius * 2) / (app.radius * 2)) * 0.3 + 0.7;
				
			// scale
			scaleX = scaleY = scale;
			
			// position
			x = billboard.screen.x;
			y = billboard.screen.y;
			
			var zClip = 220 * app.zoomScale;
			
			// show node if on front of globe
			if (tempPos.z < zClip) {
				visible = true;
			// hide node if behind globe
			} else if (tempPos.z > (zClip - 1)) {
				visible = false;
			}
		}
		
		// TEXT DISPLAY (initialize) ///////////////////////////////////////////////// 
		private function initTextDisplay():void {
			
			var showTitle:Boolean = true;
			
			if (showTitle) {
				
				// text formatting
				var format:TextFormat 				= new TextFormat();
				format.font 		  				= "Helvetica"; 
				format.color 		  				= 0xFFFFFF;
				format.size 		  				= 12;
				format.align 	      				= "left";
				
				// title text
				titleTextField 						= new TextField();
				titleTextField.y 					= -8;
				titleTextField.x 					= 15;
				titleTextField.autoSize 			= "left";
				titleTextField.selectable 			= false;
				titleTextField.defaultTextFormat 	= format;
				titleTextField.visible 				= true;
				titleTextField.text 				= title;
				addChild(titleTextField);
			}
		}
		
		// EVENT HANDLERS ///////////////////////////////////////////////////////////////
		public function clickHandler(event:MouseEvent):void {
			
			if (app.winOpen == true) {
				closeWindow();
				openWindow();
				addPointer();
			}
			if (app.winOpen == false) {
				openWindow();
				addPointer();
			}
			
		}
		
		public function mouseOverHandler(event:MouseEvent):void {
			app.highlightNode(nodeID, true);
		}
		
		public function mouseOutHandler(event:MouseEvent):void {
			app.highlightNode(nodeID, false);
		}
	
		// GROW /////////////////////////////
		public function grow():void {
			this.scaleX = origXScale * 1.6;
			this.scaleY = origYScale * 1.6;
		}
		
		// SHRINK ////////////////////////////
		public function shrink():void {
			this.scaleX = origXScale;
			this.scaleY = origYScale;
		}
		
		// OPEN WINDOW ////////////////////////////////////////////////////////////////////////
		public function openWindow():void {
			
			var winMode:String = type;
			
			var win:WinDisplay = new WinDisplay({
								 
								// content
								winMode		:winMode,
								title		:title,
								contentPath	:contentPath,
								colorCode   :colorCode,
								
								// ref
								appNode		:this,
								app			:app
								
								});
			
			win.name = "window";
			app.container.addChild(win);
	
			app.winOpen = true;
		}
		
		// ADD POINTER ////////////////////////////////////////////////////////////////////////
		private function addPointer():void {
			var pointer:Pointer = new Pointer({appNode:this});
			pointer.name = "pointer";
			app.container.addChild(pointer);
		}
		
		// CLOSE WINDOW ////////////////////////////////////////////////////////////////////////
		public function closeWindow():void {
			// remove pointer
			var rPointer:DisplayObject = app.container.getChildByName("pointer"); 	
			app.container.removeChild(rPointer);
			// remove window
			var rWin:DisplayObject = app.container.getChildByName("window"); 	
			app.container.removeChild(rWin);
			app.winOpen = false;
		}
		
		// MAKE INVISIBLE  /////////////////////////////////////////////////////////////////////
		public function makeInvisible():void {
			this.point.visible = false;
			this.shadowpoint.visible = false;
			//
			removeEventListener(MouseEvent.CLICK, clickHandler);
			removeEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
			removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
			//
			//removeChild(titleTextField);
		}
	}
}